package com.ashokvarma.sample; import android.support.test.espresso.PerformException; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.action.CoordinatesProvider; import android.support.test.espresso.action.GeneralLocation; import android.support.test.espresso.action.GeneralSwipeAction; import android.support.test.espresso.action.Press; import android.support.test.espresso.action.Swipe; import android.support.test.espresso.util.HumanReadables; import android.support.test.espresso.util.TreeIterables; import android.view.View; import org.hamcrest.Matcher; import java.util.concurrent.TimeoutException; import static android.support.test.espresso.action.ViewActions.actionWithAssertions; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static android.support.test.espresso.matcher.ViewMatchers.withId; /** * Class description * * @author ashokvarma * @version 1.0 * @see * @since 26 May 2016 */ public class Utils { /** * The distance of a swipe's start position from the view's edge, in terms of the view's length. * We do not start the swipe exactly on the view's edge, but somewhat more inward, since swiping * from the exact edge may behave in an unexpected way (e.g. may open a navigation drawer). */ private static final float EDGE_FUZZ_FACTOR = 0.083f; /** * Perform action of waiting for a specific view id. */ public static ViewAction waitId(final int viewId, final long millis) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return isRoot(); } @Override public String getDescription() { return "wait for a specific view with id <" + viewId + "> during " + millis + " millis."; } @Override public void perform(final UiController uiController, final View view) { uiController.loopMainThreadUntilIdle(); final long startTime = System.currentTimeMillis(); final long endTime = startTime + millis; final Matcher<View> viewMatcher = withId(viewId); do { for (View child : TreeIterables.breadthFirstViewTraversal(view)) { // found view with required ID if (viewMatcher.matches(child)) { return; } } uiController.loopMainThreadForAtLeast(50); } while (System.currentTimeMillis() < endTime); // timeout happens throw new PerformException.Builder() .withActionDescription(this.getDescription()) .withViewDescription(HumanReadables.describe(view)) .withCause(new TimeoutException()) .build(); } }; } /** * Returns an action that performs a swipe right-to-left across the vertical center of the * view. The swipe doesn't start at the very edge of the view, but is a bit offset.<br> * <br> * View constraints: * <ul> * <li>must be displayed on screen * <ul> */ public static ViewAction swipeLeftSlow() { return actionWithAssertions(new GeneralSwipeAction(Swipe.SLOW, translate(GeneralLocation.CENTER_RIGHT, -EDGE_FUZZ_FACTOR, 0), GeneralLocation.CENTER_LEFT, Press.FINGER)); } /** * Returns an action that performs a swipe left-to-right across the vertical center of the * view. The swipe doesn't start at the very edge of the view, but is a bit offset.<br> * <br> * View constraints: * <ul> * <li>must be displayed on screen * <ul> */ public static ViewAction swipeRightSlow() { return actionWithAssertions(new GeneralSwipeAction(Swipe.SLOW, translate(GeneralLocation.CENTER_LEFT, EDGE_FUZZ_FACTOR, 0), GeneralLocation.CENTER_RIGHT, Press.FINGER)); } /** * Returns an action that performs a swipe top-to-bottom across the horizontal center of the view. * The swipe doesn't start at the very edge of the view, but has a bit of offset.<br> * <br> * View constraints: * <ul> * <li>must be displayed on screen * <ul> */ public static ViewAction swipeDownSlow() { return actionWithAssertions(new GeneralSwipeAction(Swipe.SLOW, translate(GeneralLocation.TOP_CENTER, 0, EDGE_FUZZ_FACTOR), GeneralLocation.BOTTOM_CENTER, Press.FINGER)); } /** * Returns an action that performs a swipe bottom-to-top across the horizontal center of the view. * The swipe doesn't start at the very edge of the view, but has a bit of offset.<br> * <br> * View constraints: * <ul> * <li>must be displayed on screen * <ul> */ public static ViewAction swipeUpSlow() { return actionWithAssertions(new GeneralSwipeAction(Swipe.SLOW, translate(GeneralLocation.BOTTOM_CENTER, 0, -EDGE_FUZZ_FACTOR), GeneralLocation.TOP_CENTER, Press.FINGER)); } /** * Translates the given coordinates by the given distances. The distances are given in term * of the view's size -- 1.0 means to translate by an amount equivalent to the view's length. */ static CoordinatesProvider translate(final CoordinatesProvider coords, final float dx, final float dy) { return new CoordinatesProvider() { @Override public float[] calculateCoordinates(View view) { float xy[] = coords.calculateCoordinates(view); xy[0] += dx * view.getWidth(); xy[1] += dy * view.getHeight(); return xy; } }; } }